package com.umeox.watch.moto.dataservice.utils;


import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.umeox.moto.common.log.Logger;
import com.umeox.moto.common.utils.AndroidUtils;
import com.umeox.moto.common.utils.NetUtils;
import com.umeox.watch.location.proto.LocationProto;
import com.umeox.watch.location.proto.LocationProto.LocMode;
import com.umeox.watch.location.proto.LocationProto.LocationDetail;
import com.umeox.watch.moto.dataservice.BuildConfig;
import com.umeox.watch.moto.dataservice.DataProvider;
import com.umeox.watch.moto.dataservice.base.BaseApp;
import com.umeox.watch.moto.dataservice.constants.Constants;
import com.umeox.watch.moto.dataservice.observer.CellInfoObserver;
import com.umeox.watch.moto.dataservice.services.LocationService;

import org.jetbrains.annotations.NotNull;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 采用Android location方式
 * 网络定位优先，网络定位失败使用GPS定位，GPS定位失败再网络定位一次
 */

public class LocationHelper {
    private static final String TAG = LocationService.TAG + "->Helper";

    private LocationManager locationManager;
    //3分钟定位超时
    private int millisInFuture = 3 * 60 * 1000;

    private AtomicInteger timeoutCount;
    private ScheduledThreadPoolExecutor timerExecutor;
    private ScheduledFuture timerFuture;

    private LocationCallback locationCallback = null;

    private Handler mainHandler;
    private PowerManager.WakeLock mWakeLock = null;

    private WeakReference<Context> contextRefrence;
    private LocationCompleteListener locListener;
    private AtomicBoolean isWorking;

    private LocationDetail.Builder locBuilder;

    private LocationHelper(Context context) {
        contextRefrence = new WeakReference<>(context);
        isWorking = new AtomicBoolean(false);
    }

    public static LocationHelper getHelper(Context context) {
        return new LocationHelper(context);
    }

    private Context getContext() {
        return contextRefrence.get();
    }

    private LocationCompleteListener getLocListener() {
        return locListener;
    }

    public void setLocListener(LocationCompleteListener locListener) {
        this.locListener = locListener;
    }

    private Handler getMainHandler() {
        if (mainHandler == null) {
            synchronized (this) {
                if (mainHandler == null) {
                    mainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        return mainHandler;
    }

    public boolean isWorking() {
        return isWorking.get();
    }

    private void onStateChange(String message) {
        if (getLocListener() != null) {
            getLocListener().onStateChange(message);
        }
    }

    public void requestLocation(LocationDetail.Builder builder) {
        if (isWorking.compareAndSet(false, true)) {
            locBuilder = builder;
            locBuilder.setLat(-999d).setLng(-999d).setAccuracy(0);

            timeoutCount = new AtomicInteger(0);
            //唤醒CPU
            acquireWakeLock();

            if (!Utils.isLocationEnabled(getContext())) {
                Logger.w(TAG + ">>>定位服务不可用，打开位置服务");
                LogUtils.saveLog(TAG + ">>>定位服务不可用，打开位置服务");
                Utils.setHighAccuracyLocationMode(getContext());
            }
            if (locBuilder.getLocPriority() == LocationProto.LocPriority.PRIORITY_GPS_VALUE) {
                //GPS定位优先
                locBuilder.setOrder(132);
            } else {
                if (locBuilder.getLocReason() == LocationProto.LocReason.forNumber(LocationProto.LocReason.SOS_LOCATION_VALUE)) {
                    locBuilder.setOrder(32);
                } else {
                    locBuilder.setOrder(321);
                }
            }

            if (DataProvider.getLocMethod() == 0) {
                if (locBuilder.getLocPriority() == LocationProto.LocPriority.PRIORITY_GPS_VALUE) {
                    //GPS定位优先
                    requestLocationByGPS(getContext());
                } else {
                    requestLocationByNETWORK(getContext());
                }
            } else {
                if (Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId()) {
                    requestLocationByAmap();
                } else {
                    getMainHandler().post(this::requestLocationByAmap);
                }
            }


        }
    }

    //取消当前定位任务
    public void cancel() {
        if (isWorking()) {
            Logger.w(TAG + ">>>取消当前定位");
            locationFailed("主动取消当前定位");
        }
    }

    //Android SDK定位
    @SuppressLint("MissingPermission")
    private void requestLocationByGPS(Context context) {
        if (context == null) {
            locationFailed("定位服务已销毁");
            return;
        }
        if (BuildConfig.DEBUG) {
            onStateChange("开始GPS定位");
        }
        //判断GPS是否可以，不可以打开它
        if (!isProviderEnabled(context, LocationManager.GPS_PROVIDER)) {
            Utils.setHighAccuracyLocationMode(getContext());
        }
        //设置GPS定位超时时间
        millisInFuture = BuildConfig.GPS_TIMEOUT_TIMEMILLIS;
        //注册监听器
        //注册监听器
        locationCallback = new LocationCallback();

        //经测试采用requestSingleUpdate方法无法定义，原因未知
        // 第一个参数，定义当前所使用的Location Provider
        // 第二个参数，指示更新的最小时间，但并不是确定的，可能更多或更小
        // 第三个参数，两次定位之间的最小距离，单位米。
        // 第四个参数，监听器
        if (Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId()) {
            Logger.i(TAG + ">>>当前已经是主线程，直接定位");
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationCallback);
            startCountDownTimer();
        } else {
            Logger.i(TAG + ">>>当前为子线程，切换到主线程定位");
            getMainHandler().post(() -> {
                if (isWorking()) {
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationCallback);
                    startCountDownTimer();
                }
            });
        }
    }

    private boolean isProviderEnabled(Context context, String provider) {
        if (locationManager == null) {
            locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        }
        if (LocationManager.GPS_PROVIDER.equals(provider)) {
            /*
            //冷启动
            Bundle bundle = null;
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "force_xtra_injection", bundle);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "force_time_injection", bundle);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", bundle);

            //温启动
            Bundle bundleWarm = new Bundle();
            bundleWarm.putBoolean("ephemeris", true);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "force_xtra_injection", bundleWarm);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "force_time_injection", bundleWarm);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", bundleWarm);
            */
            //热启动
            Bundle bundleHot = new Bundle();
            bundleHot.putBoolean("almanac", true);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "force_xtra_injection", bundleHot);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "force_time_injection", bundleHot);
            locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", bundleHot);
        }
        return locationManager != null &&
                locationManager.isProviderEnabled(provider);
    }

    private void requestLocationByNETWORK(Context context) {
        if (context == null) {
            locationFailed("定位服务已销毁");
            return;
        }
        if (NetUtils.isNetworkAvailable()) {
            //判断网络定位服务是否可以，不可以切换定位模式
            if (!isProviderEnabled(context, LocationManager.NETWORK_PROVIDER)) {
                Utils.setHighAccuracyLocationMode(getContext());
            }
            //设置定位超时时间
            millisInFuture = BuildConfig.NETWORK_TIMEOUT_TIMEMILLIS;

            locationSuccessful(LocMode.WIFI, -999, -999, -1, 0, 0, "");
        } else if (timeoutCount.get() == 0) {
            Logger.w(TAG + ">>>没有网络，切换到GPS定位");
            requestLocationByGPS(context);
        } else {
            Logger.w(TAG + ">>>没有网络，定位失败");
            locationFailed("没有网络，定位失败");
        }
    }

    private void startCountDownTimer() {
        if (timerExecutor == null) {
            timerExecutor = new ScheduledThreadPoolExecutor(5,
                    new ThreadFactory() {
                        private AtomicInteger count = new AtomicInteger(0);

                        @Override
                        public Thread newThread(@NonNull Runnable r) {
                            Thread thread = new Thread(r);
                            thread.setName("Location-Countdown-" + count.addAndGet(1));
                            return thread;
                        }
                    });
            //延时的schedule在shutdown后，不会继续执行没到时间的任务
            // 默认是true，会执行一次正在倒计时的任务再结束
            timerExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
            //延时的scheduleAtFixedRate/scheduleWithFixedDelay在shutdown后，不会继续执行没到时间的任务
            // 默认是true，会执行一次正在倒计时的任务再结束
            timerExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
        }

        //取消当前任务
        if (timerFuture != null && !timerFuture.isCancelled()) {
            timerFuture.cancel(true);
        }
        //获取未完成的任务队列
        BlockingQueue<Runnable> queues = timerExecutor.getQueue();
        if (queues != null && !queues.isEmpty()) {
            Runnable task = queues.poll();
            while (task != null) {
                timerExecutor.remove(task);
                task = queues.poll();
            }
        }
        timerFuture = timerExecutor.scheduleAtFixedRate(new LocationTimeOut(LocationManager.GPS_PROVIDER), 1, 1, TimeUnit.SECONDS);
    }

    private void unregisterLocationUpdates() {
        if (timerFuture != null) {
            boolean result = timerFuture.cancel(true);
            Logger.d(TAG + ">>>取消倒计时任务->" + result);
        }

        if (locationManager != null && locationCallback != null) {
            locationManager.removeUpdates(locationCallback);
            locationCallback = null;
            locationManager = null;
            Logger.d(TAG + ">>>移除GPS定位回调函数");
        }

        if (mLocationClient != null) {
            mLocationClient.stopLocation();
            mLocationClient.onDestroy();
            mLocationClient = null;
            mAMapLocation = null;
        }
    }

    private LocMode getLocMode(String provider) {
        switch (provider) {
            case LocationManager.GPS_PROVIDER:
                return LocMode.GPS;
            case LocationManager.NETWORK_PROVIDER:
                return LocMode.WIFI;
            default:
                return LocMode.LBS;
        }
    }


    private void firstLocationSuccessful(LocMode locMode, double latitude, double longitude, float accuracy, float speed, int coordType, String address) {
        Logger.d(TAG, "第一次位置回调成功");
        LogUtils.saveLog("第一次位置回调成功");
        String currentCellTower;
        List<String> nearCellTowers;
        List<LocationProto.WifiPoint> wifiPoints;
        try {
            currentCellTower = CellInfoObserver.getInstance().getCurrentCellTower();
        } catch (Exception e) {
            e.printStackTrace();
            currentCellTower = "";
        }
        try {
            nearCellTowers = CellInfoObserver.getInstance().getNearByCellTowers();
        } catch (Exception e) {
            e.printStackTrace();
            nearCellTowers = null;
        }
        try {
            wifiPoints = Utils.getWifiPoints();
        } catch (Exception e) {
            e.printStackTrace();
            wifiPoints = null;
        }
        locBuilder.setLocMode(locMode)
                .setLat(latitude == 0.0 ? -999 : latitude)
                .setLng(longitude == 0.0 ? -999 : longitude)
                .setAccuracy(accuracy)
                .setBattery(BaseApp.getInstance().getBatteryLevel())
                .setEndTime(Calendar.getInstance().getTimeInMillis())
                .setCellTower(currentCellTower)
                .addAllNearbyCellTowers(nearCellTowers)
                .addAllWifiPoints(wifiPoints)
                .setNetwork(NetUtils.getNetworkTypeName())
                .setSpeed(speed)
                .setCoordType(coordType)
                .setAddress(address)
                .setHolderId(TextUtils.isEmpty(DataProvider.getHolderId()) ? AndroidUtils.getDeviceId() : DataProvider.getHolderId())
                .setCharge(BaseApp.getInstance().isCharging());

        if (getLocListener() != null) {
            getLocListener().onFirstLocationSuccess(locBuilder);
        }
    }


    private void locationSuccessful(LocMode locMode, double latitude, double longitude, float accuracy, float speed, int coordType, String address) {
        Logger.d(TAG, "定位成功");
        LogUtils.saveLog("定位成功");
        String currentCellTower;
        List<String> nearCellTowers;
        List<LocationProto.WifiPoint> wifiPoints;
        try {
            currentCellTower = CellInfoObserver.getInstance().getCurrentCellTower();
        } catch (Exception e) {
            e.printStackTrace();
            currentCellTower = "";
        }
        try {
            nearCellTowers = CellInfoObserver.getInstance().getNearByCellTowers();
        } catch (Exception e) {
            e.printStackTrace();
            nearCellTowers = null;
        }
        try {
            wifiPoints = Utils.getWifiPoints();
        } catch (Exception e) {
            e.printStackTrace();
            wifiPoints = null;
        }
        locBuilder.setLocMode(locMode)
                .setLat(latitude == 0.0 ? -999 : latitude)
                .setLng(longitude == 0.0 ? -999 : longitude)
                .setAccuracy(accuracy)
                .setBattery(BaseApp.getInstance().getBatteryLevel())
                .setEndTime(Calendar.getInstance().getTimeInMillis())
                .setCellTower(currentCellTower)
                .addAllNearbyCellTowers(nearCellTowers)
                .addAllWifiPoints(wifiPoints)
                .setNetwork(NetUtils.getNetworkTypeName())
                .setSpeed(speed)
                .setCoordType(coordType)
                .setAddress(address)
                .setHolderId(DataProvider.getHolderId())
                .setCharge(BaseApp.getInstance().isCharging());

        locationCompleted();

        if (getLocListener() != null) {
            getLocListener().onLocationSuccess(locBuilder);
        } else {
            LogUtils.saveLog("getLocListener == NULL");
        }

    }

    private int getCoordType(String coordType) {
        if (TextUtils.isEmpty(coordType)) {
            return 0;
        }

        if (AMapLocation.COORD_TYPE_WGS84.equals(coordType)) {
            return 1;
        } else if (AMapLocation.COORD_TYPE_GCJ02.equals(coordType)) {
            return 2;
        }
        return 0;
    }

    private void locationFailed(String errorMsg) {
        Logger.d(TAG, "定位失败" + errorMsg);
        LogUtils.saveLog("定位失败:" + errorMsg);
        String currentCellTower;
        List<String> nearCellTowers;
        List<LocationProto.WifiPoint> wifiPoints;
        try {
            currentCellTower = CellInfoObserver.getInstance().getCurrentCellTower();
        } catch (Exception e) {
            e.printStackTrace();
            currentCellTower = "";
        }
        try {
            nearCellTowers = CellInfoObserver.getInstance().getNearByCellTowers();
        } catch (Exception e) {
            e.printStackTrace();
            nearCellTowers = new ArrayList<>();
        }
        try {
            wifiPoints = Utils.getWifiPoints();
        } catch (Exception e) {
            e.printStackTrace();
            wifiPoints = new ArrayList<>();
        }
        locBuilder.setLocMode(LocMode.WIFI)
                .setBattery(BaseApp.getInstance().getBatteryLevel())
                .setCellTower(currentCellTower)
                .addAllNearbyCellTowers(nearCellTowers)
                .addAllWifiPoints(wifiPoints)
                .setEndTime(Calendar.getInstance().getTimeInMillis())
                .setNetwork(NetUtils.getNetworkTypeName())
                .setCharge(BaseApp.getInstance().isCharging())
                .setHolderId(DataProvider.getHolderId())
                .setLocReasonAttr(errorMsg);

        locationCompleted();

        if (getLocListener() != null) {
            getLocListener().onLocationFailed(locBuilder);
        } else {
            LogUtils.saveLog("getLocListener == NULL");
        }

    }

    private void locationCompleted() {
        isWorking.set(false);
        if (BuildConfig.DEBUG) {
            onStateChange("定位完成");
        }
        //移除有所监听
        unregisterLocationUpdates();
        //释放CPU锁
        releaseWakeLock();
        //关闭计时线程池
        if (timerExecutor != null) {
            timerExecutor.shutdownNow();
        }
        //通知GC回收
        System.gc();
    }

    private void sendBroadcast(double lat, double longitude) {
        //纬度,经度
        Intent intent = new Intent();
        intent.setAction(Constants.ACTION_LOCATION_SUCCESS);
        intent.putExtra("LAT", String.valueOf(lat));
        intent.putExtra("LONG", String.valueOf(longitude));
        BaseApp.getInstance().sendBroadcast(intent);
        Logger.w(TAG + ">>>定位成功，将经纬度通过广播发送");
    }

    //申请设备电源锁
    private void acquireWakeLock() {
        Logger.i(TAG + ">>>申请设备电源锁");
        LogUtils.saveLog(TAG + ">>>申请设备电源锁");
        if (null == mWakeLock) {
            PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
            if (pm != null) {
                mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, LocationHelper.class.getSimpleName());
            }
            if (null != mWakeLock) {
                mWakeLock.acquire(millisInFuture);
            }
        }
    }

    //释放设备电源锁
    private void releaseWakeLock() {
        if (mWakeLock != null) {
            Logger.w(TAG + ">>>Releasing wakelock");
            try {
                mWakeLock.release();
            } catch (Throwable th) {
                // ignoring this exception, probably wakeLock was already released
            }
        } else {
            // should never happen during normal workflow
            Logger.w(TAG + ">>>Wakelock reference is null");
        }
        mWakeLock = null;
    }

    public interface LocationCompleteListener {
        void onStateChange(String message);

        void onFirstLocationSuccess(LocationDetail.Builder locBuilder);

        void onLocationSuccess(LocationDetail.Builder locBuilder);

        void onLocationFailed(LocationDetail.Builder locBuilder);
    }

    /**
     * 开启定位倒计时
     */
    private class LocationTimeOut extends TimerTask {
        private int times = 0;

        LocationTimeOut(String provider) {
            this.times = 0;
        }

        @Override
        public void run() {
            times += 1;
            Logger.d(TAG + ">>>超时时间:" + millisInFuture / 1000 + "秒;定位耗时：" + times);
            LogUtils.saveLog(TAG + ">>>超时时间:" + millisInFuture / 1000 + "秒;定位耗时：" + times);

            if (getContext() == null) {
                Logger.d(TAG + "定位服务已销毁");
                locationFailed("定位服务已销毁");
                return;
            }

            if (times == (millisInFuture / 1000 - 25)) {
                WifiManager wifiManager = (WifiManager) getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
                boolean isWifiScanAlwaysAvailable = wifiManager.isScanAlwaysAvailable();
                Logger.e("isWifiScanAlwaysAvailable=" + isWifiScanAlwaysAvailable);
                if (!isWifiScanAlwaysAvailable) {
                    Settings.Global.putInt(getContext().getContentResolver(),
                            "wifi_scan_always_enabled", 1);
                }
            }

            //GPS定位，当快要超时的时候，提前20秒钟打开WIFI
            if (times == (millisInFuture / 1000 - 20)) {
                boolean isWifiEnabled = Utils.isWifiEnabled(getContext());
                if (!isWifiEnabled) {
                    Logger.d(TAG + ">>>GPS定位快要超时了，提前打开WIFI");
                    if (getContext() instanceof LocationService) {
                        ((LocationService) getContext()).enableWIFI(true);
                    } else {
                        enableWIFI();
                    }
                }
                scanWifi();
            }
            if (times == millisInFuture / 1000) {
                if (DataProvider.getLocMethod() == 0) {
                    //定位超时
                    if (timeoutCount.incrementAndGet() < 2) {
                        //GPS定位超时，注册网络监听器重新定位
                        onStateChange("GPS定位超时");
                        unregisterLocationUpdates();
                        requestLocationByNETWORK(getContext());
                    } else {
                        //定位超时
                        locationFailed("定位超时");
                    }
                    return;
                }

                if (mAMapLocation != null) {
                    onAMapLocationSuccessful(mAMapLocation);
                    unregisterLocationUpdates();
                } else {
                    locationFailed("定位超时");
                }
            }
        }

        private void enableWIFI() {
            try {
                NetUtils.setWifiEnabled(true);
            } catch (Exception ignored) {
            }
            scanWifi();
        }

        private void scanWifi() {
            WifiManager wifiManager = (WifiManager) getContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
            wifiManager.startScan();
        }
    }

    private class LocationCallback implements android.location.LocationListener {

        //用户位置改变监听器
        // 当坐标改变时触发此函数，如果Provider传进相同的坐标，它就不会被触发
        @Override
        public void onLocationChanged(Location location) {
            if (BuildConfig.DEBUG) {
                onStateChange("GPS定位，位置发生改变");
            }
            if (location != null) {
                Logger.w(TAG + ">>>Location changed : Provider: " + location.getProvider() + " Lat: " + location.getLatitude() + " Lng: " + location.getLongitude());
                LogUtils.saveLog(">>>Location changed : Provider: " + location.getProvider() + " Lat: " + location.getLatitude() + " Lng: " + location.getLongitude());
                locationSuccessful(getLocMode(location.getProvider()), location.getLatitude(), location.getLongitude(), location.getAccuracy(), location.getSpeed(), 1, "");
                try {
                    sendBroadcast(location.getLatitude(), location.getLongitude());
                } catch (Exception ignored) {

                }
            }
        }


        // Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            if (BuildConfig.DEBUG) {
                onStateChange("Provider状态改变");
            }
            Logger.d(TAG + ">>>onStatusChanged status:" + status);
            // No need to care about, because any thing like OUT_OF_SERVICE occurs,
            // location being fetched will be null and such cases are handled above.
            if ((provider.equals(LocationManager.GPS_PROVIDER))
                    && (LocationProvider.OUT_OF_SERVICE == status)) {
                if (BuildConfig.DEBUG) {
                    onStateChange("GPS服务丢失,切换至网络定位");
                }
                //GPS服务丢失,切换至网络定位
                unregisterLocationUpdates();
                requestLocationByNETWORK(getContext());
            }
        }

        // Provider被enable时触发此函数，比如GPS被打开
        @Override
        public void onProviderEnabled(String provider) {
            Logger.w(TAG + ">>>Location Provider Enabled");
        }

        // Provider被disable时触发此函数，比如GPS被关闭
        @Override
        public void onProviderDisabled(String provider) {
            Logger.w(TAG + ">>>Get Better Location, Location Provider Disabled");
        }
    }

    public AMapLocationClient mLocationClient = null;

    /**
     * 使用高德定位
     */
    private void requestLocationByAmap() {
        //设置GPS定位超时时间
        Logger.d(TAG, "requestLocationByAmap isProviderEnabled:" + isProviderEnabled(getContext(), LocationManager.GPS_PROVIDER));
        Settings.Secure.putInt(getContext().getContentResolver(), Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
        millisInFuture = BuildConfig.GPS_TIMEOUT_TIMEMILLIS;
        mLocationClient = new AMapLocationClient(getContext());
        AMapLocationClientOption locationClientOption = new AMapLocationClientOption();
        locationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        locationClientOption.setGpsFirstTimeout(BuildConfig.GPS_TIMEOUT_TIMEMILLIS);
        locationClientOption.setGpsFirst(true);
        locationClientOption.setHttpTimeOut(30000);
        locationClientOption.setInterval(2000);
        mLocationClient.setLocationOption(locationClientOption);
        mLocationClient.setLocationListener(new AMapLocationCallback());
        mLocationClient.startLocation();
        startCountDownTimer();
    }

    private AMapLocation mAMapLocation;


    private class AMapLocationCallback implements AMapLocationListener {

        @Override
        public void onLocationChanged(AMapLocation loc) {
            Logger.d(TAG, "AMapLocationListener$onLocationChanged " + loc);
            LogUtils.saveLog("AMapLocationCallback:" + loc.toString());

            if (loc == null) {
                return;
            }

            final int locationType = loc.getLocationType();
            if (mAMapLocation != null) {
                final int lastLocationType = mAMapLocation.getLocationType();
                if (locationType == AMapLocation.LOCATION_TYPE_SAME_REQ || locationType == AMapLocation.LOCATION_TYPE_FIX_CACHE) {
                    loc.setLocationType(lastLocationType);
                }
            }

            if (loc.getErrorCode() == AMapLocation.LOCATION_SUCCESS) {
//                if(locBuilder.getLocReason() == LocationProto.LocReason.CMD_LOCATION){ //定位成功，CMD定位
//                    LocMode locMode = getLocMode(loc);
//                    firstLocationSuccessful(locMode, loc.getLatitude(), loc.getLongitude(), loc.getAccuracy(), loc.getSpeed(), getCoordType(loc.getCoordType()), loc.getAddress());
//                }
                mAMapLocation = loc;

                if (locBuilder.getLocPriority() == LocationProto.LocPriority.PRIORITY_GPS_VALUE) {
                    if (locationType == AMapLocation.LOCATION_TYPE_GPS) {
                        onAMapLocationSuccessful(loc);
                        unregisterLocationUpdates();
                    }
                } else {
                    onAMapLocationSuccessful(loc);
                    unregisterLocationUpdates();
                }
            } else {
                //locationFailed(loc.getErrorInfo());
                LogUtils.saveLog("AMapLocationCallback:" + loc.getErrorInfo());
                //Utils.ping("apilocate.amap.com");
                if (mAMapLocation == null) {
                    mAMapLocation = loc;
                }
            }
        }
    }


    private void onAMapLocationSuccessful(AMapLocation loc) {
        try {
            sendBroadcast(loc.getLatitude(), loc.getLongitude());
            LocMode locMode = getLocMode(loc);
            locationSuccessful(locMode, loc.getLatitude(), loc.getLongitude(), loc.getAccuracy(), loc.getSpeed(), getCoordType(loc.getCoordType()), loc.getAddress());
        } catch (Exception e) {
            Logger.e(TAG, "onAMapLocationSuccessful: ", e);
        }
    }

    @NotNull
    private LocMode getLocMode(AMapLocation loc) {
        LocMode locMode = LocMode.UNKNOWN;
        final int locationType = loc.getLocationType();
        switch (locationType) {
            case AMapLocation.LOCATION_TYPE_GPS:
                locMode = LocMode.GPS;
                break;
            case AMapLocation.LOCATION_TYPE_WIFI:
                locMode = LocMode.WIFI;
                break;
            case AMapLocation.LOCATION_TYPE_SAME_REQ:
            case AMapLocation.LOCATION_TYPE_FIX_CACHE:
            case AMapLocation.LOCATION_TYPE_CELL:
                locMode = LocMode.LBS;
                break;
            case AMapLocation.LOCATION_TYPE_LAST_LOCATION_CACHE:
            case AMapLocation.LOCATION_TYPE_AMAP:
            case AMapLocation.LOCATION_TYPE_OFFLINE:
                locMode = LocMode.MIX;
                break;
            default:
                break;
        }
        return locMode;
    }

}
